/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "WorkCfg.h"
#include "ScanPacket.h"
#include "ListOfPorts.h"
#include "ListOfAddresses.h"
#include "PacketBuilderEx.h"
#include "PacketBuilderEx6.h"
#include "MWinPcap.h"
#include "ScanMessages.h"
#include "mt19937.h"
#include "MMachineInfoList.h"
#include "MArpCacheList.h"
#include "MWmiWorker.h"

#include "PacketBuilderPromisc.h"

#define MAX_CAPTURED_PACKET_SIZE 2048
#define RANDOM_VALUES_COUNT      32

enum ScanPairType
{
	__sptIpOnly,
	__sptIpAndPort,
	__sptIpAndPromisc
};

/*! \brief Holds informations for a single scan
*/
struct ScanPair
{
	MFullAddress* addr;
	WORD          port;
};

/*! \brief The parameters needed for a scan method to start
*/
struct ScanStartParameters
{
	MWinPcap			 *sspWinPcap;
	PacketBuilderEx		 *sspPackBuilderEx;
	PacketBuilderEx6     *sspPackBuilderEx6;
	PacketBuilderPromisc *sspPacketBuilderPromisc;
	WorkCfg				 *sspWorkCfg;			/*config*/
	CString				 sspData;				/*WorkCfgElement::data*/;
	MArpCacheList		 *sspArpCacheList;
	ListOfAddresses		 *sspListOfAddr;
	MMachineInfoList	 *sspMachInfoList;
	WorkPhaseType		 sspWorkPhase;
	HWND				 sspMsgWnd;
	int					 sspNotifTcp;
	int					 sspNotifUdp;
	int					 sspNotifPing;
	int					 sspNotifNetBios;
	MWMIWorker           *sspWmiWorker;
};


#define RCV_HDR_HOPBYHOP 0x0001

/*! \brief The base class for all scanning methods
*/
class ScanMethod
{
private:

protected:
	WorkMethodType myType;
	MimicOS myMimic;

	bool isStarted;

	ScanPacket* packets;
	int scanPackCnt;
		bool CreatePackets(void);
		void DestroyPackets(void);
		ScanPacket* FindPacket(DWORD /*IPv4 address*/, WORD /*port*/, WorkMethodType);
		bool IsSameAddr6(in_addr6*, in_addr6*);
		ScanPacket* FindPacket6(in_addr6* /*addr*/, WORD /*port*/, WorkMethodType);
		ScanPacket* FindFirstUnusedPacket(void);
		int PacketsUsed(void);

	DWORD ComputeDeltaTime(DWORD /*startTime*/, DWORD /*endTime*/);
	DWORD lastScanTime, scanTime;
	bool waitDone;

	MWinPcap        *winPcap;
	WorkCfg         *config;
	MArpCacheList   *arpCacheList;
	ListOfAddresses *addrList;
	CString         scanParameters;
	DWORD           waitTime;
	MWMIWorker      *wmiWorker;
	BYTE            igmpMaxResponseTime;

	int notifTcp;
	int notifUdp;
	int notifPing;
	int notifNetBios;

	virtual int InternalInit(void);
	virtual int InternalExecute(void);
	virtual int InternalDeath(ScanPacket*);

	void CheckDeaths(void);

	bool SendPacket(BYTE*, int);
	PacketBuilderEx      *packetBuilderEx;
	PacketBuilderEx6     *packetBuilderEx6;
	PacketBuilderPromisc *packetBuilderPromisc;

	BYTE capPacket[MAX_CAPTURED_PACKET_SIZE];
	int  capPackSize;
	BYTE arpReplySignature[10];
	int  ReadPacket(void);
	bool CheckResponses(void);

	void ProcessIpPacket(BYTE*, int, BYTE*);
		virtual void ProcessArpAny(BYTE*, int);
		virtual void ProcessArpReply(BYTE*, int);
		void ProcessIcmp(BYTE*, int, BYTE*);
			virtual void ProcessEchoReply(BYTE*, int);
			virtual void ProcessEchoReplyEx(BYTE*, int, BYTE*);
			virtual void ProcessHostUnreacheable(BYTE*, int);
			virtual void ProcessProtocolUnreacheable(BYTE*, int);
			virtual void ProcessPortUnreacheable(BYTE*, int);
			virtual void ProcessIcmpAny(BYTE*, int, BYTE*);
		virtual void ProcessIgmp(BYTE*, int, BYTE*);
		virtual void ProcessTcp(BYTE*, int, BYTE*);
		virtual void ProcessUdp(BYTE*, int);
		virtual void ProcessUdpEx(BYTE*, int, BYTE*);
		virtual void ProcessOtherIpPacket(BYTE*, int, BYTE*);

	DWORD receivedHeaders;
	void ProcessIPv6Packet(BYTE*, int, BYTE*);
		void ProcessIcmp6(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessDestinationUnreachable6(BYTE*, int, BYTE*);
			virtual void ProcessPortUnreachable6(BYTE*, int, BYTE*);
			virtual void ProcessErrHeaderField(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessUnkNextHeader(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessUnkIPv6Option(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessEchoReply6(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessMulticastListenerReport(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessRouterAdvertisement(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessNeighborAdvertisement(BYTE*, int, BYTE*, BYTE*);
			virtual void ProcessIcmp6Any(BYTE*, int, BYTE*, BYTE*);
		virtual void ProcessTcp6(BYTE*, int, BYTE*, BYTE*);
		virtual void ProcessUdp6(BYTE*, int, BYTE*, BYTE*);
		virtual void ProcessOther6Packet(BYTE*, int, BYTE*, BYTE*);

	bool Process802Dot3Frame(WORD, BYTE*, int, BYTE*, BYTE*);
		virtual void ProcessIPXorSPX(BYTE*, int, BYTE*);
		virtual void ProcessSTP(BYTE*, int, BYTE*);
		virtual void ProcessGVRP(BYTE*, int, BYTE*);
		virtual void ProcessGMRP(BYTE*, int, BYTE*);
		virtual void ProcessCDP(BYTE*, int, BYTE*);
		virtual void ProcessDTP(BYTE*, int, BYTE*);
	virtual void ProcessOtherEthernetPacket(WORD, BYTE*, int, BYTE*);

	MT19937 mt19937;
	DWORD randomVal[RANDOM_VALUES_COUNT];
	int   rndIdx;
	void  FillRandomBuffer(void);
	DWORD GetRandomValue(void);

	WorkPhaseType workPhase;

	MMachineInfoList* machInfoList;
	MMachineInfo* FindMachineByIp(DWORD);
	MMachineInfo* FindMachineByIp6(in_addr6*);

	ListOfPorts portList;
	int BuildPortList(bool asPortIn);

	int addrIdx;
	int portIdx;
	int GetAddressCount(void);
	MFullAddress* GetNextAddress(void);
	bool GetNextPair(ScanPair*, ScanPairType);
	bool GetNextPairAddrOnly(ScanPair*, ScanPairType);
	bool GetNextPairByAddr(ScanPair*, ScanPairType);
	bool GetNextPairByPort(ScanPair*, ScanPairType);
	bool GetNextPairByPromisc(ScanPair*, ScanPairType);

	virtual void ComputeRandomValues(void);

	int packSent;
	int packReceived;
	int packExpired;

	HWND hWnd;

	void ClearRespReceivedFlag(void);
	void CheckRespReceivedFlag(void);
	void SetMachineInfoRespFlag(MMachineInfo*);

	bool stopStopStop;

	bool embeddedMode;

public:
	ScanMethod(void);
	~ScanMethod(void);

	int Start(ScanStartParameters*);
	int abortReason;

	void Stop(void);

	void SetEmbeddedMode(bool);
};
